use crate::json_basic::JsonNode;

/// 遍历 json

/// 遍历object对象普通版
pub struct JsonObjectIter<'a> {
    map_iter: std::collections::hash_map::Iter<'a, String, JsonNode>,
}

/// 遍历object对象可修改版
pub struct JsonObjectMutIter<'a> {
    map_iter: std::collections::hash_map::IterMut<'a, String, JsonNode>,
}

/// 遍历object对象消耗原数据版
pub struct JsonObjectIntoIter {
    map_iter: std::collections::hash_map::IntoIter<String, JsonNode>,
}

/// 遍历array对象普通版
pub struct JsonArrayIter<'a> {
    vec_iter: std::slice::Iter<'a, JsonNode>,
}

/// 遍历array对象可修改版
pub struct JsonArrayMutIter<'a> {
    vec_iter: std::slice::IterMut<'a, JsonNode>,
}

/// 遍历array对象消耗原数据版
pub struct JsonArrayIntoIter {
    vec_iter: std::vec::IntoIter<JsonNode>,
}

impl<'a> Iterator for JsonObjectIter<'a> {
    type Item = (&'a String, &'a JsonNode);

    fn next(&mut self) -> Option<Self::Item> {
        self.map_iter.next()
    }
}

impl<'a> Iterator for JsonObjectMutIter<'a> {
    type Item = (&'a String, &'a mut JsonNode);

    fn next(&mut self) -> Option<Self::Item> {
        self.map_iter.next()
    }
}

impl Iterator for JsonObjectIntoIter {
    type Item = (String, JsonNode);

    fn next(&mut self) -> Option<Self::Item> {
        self.map_iter.next()
    }
}

impl<'a> Iterator for JsonArrayIter<'a> {
    type Item = &'a JsonNode;

    fn next(&mut self) -> Option<Self::Item> {
        self.vec_iter.next()
    }
}

impl<'a> Iterator for JsonArrayMutIter<'a> {
    type Item = &'a mut JsonNode;

    fn next(&mut self) -> Option<Self::Item> {
        self.vec_iter.next()
    }
}

impl Iterator for JsonArrayIntoIter {
    type Item = JsonNode;

    fn next(&mut self) -> Option<Self::Item> {
        self.vec_iter.next()
    }
}

impl JsonNode {
    pub fn obj_iter(&self) -> Option<JsonObjectIter> {
        match self {
            JsonNode::Object(obj) => Some(JsonObjectIter {
                map_iter: obj.iter(),
            }),
            _ => None,
        }
    }

    pub fn obj_mut_iter(&mut self) -> Option<JsonObjectMutIter> {
        match self {
            JsonNode::Object(obj) => Some(JsonObjectMutIter {
                map_iter: obj.iter_mut(),
            }),
            _ => None,
        }
    }

    pub fn obj_into_iter(self) -> Option<JsonObjectIntoIter> {
        match self {
            JsonNode::Object(obj) => Some(JsonObjectIntoIter {
                map_iter: obj.into_iter(),
            }),
            _ => None,
        }
    }

    pub fn arr_iter(&self) -> Option<JsonArrayIter> {
        match self {
            JsonNode::Array(arr) => Some(JsonArrayIter {
                vec_iter: arr.iter(),
            }),
            _ => None,
        }
    }

    pub fn arr_mut_iter(&mut self) -> Option<JsonArrayMutIter> {
        match self {
            JsonNode::Array(arr) => Some(JsonArrayMutIter {
                vec_iter: arr.iter_mut(),
            }),
            _ => None,
        }
    }

    pub fn arr_into_iter(self) -> Option<JsonArrayIntoIter> {
        match self {
            JsonNode::Array(arr) => Some(JsonArrayIntoIter {
                vec_iter: arr.into_iter(),
            }),
            _ => None,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::json_lexer;
    use crate::json_parser::parse_all;
    #[test]
    fn test_obj_iter() {
        let str = "{\"first name\":\"Yiran\", \"last name\": \"王\", \"age\":20,\"is_student\":true,\"courses\":[{\"name\":\"CPEN 212\",\"credits\":4},{\"name\":\"CPSC 221\",\"credits\":4},{\"name\":\"Math 256\",\"credits\":3}],\"address\":{\"street\":\"1935 Lower Mall\",\"city\":\"Vancouver\",\"postal_code\":\"V6T 1X1\"},\"friends\":[{\"name\":\"Tommy\",\"age\":20},{\"name\":\"Joe\",\"age\":20}],\"graduated\":false, \"university\": \"UBC\"}";
        let list = json_lexer::parse_all(str).unwrap();
        // println!("list: {:?}", list);
        let mut json_str = parse_all(list).unwrap();
        // println!("json_str: {:?}", json_str);
        let json = json_str.dump(2, false);
        // println!("json: {}", json);

        let json2 = parse_all(json_lexer::parse_all(&json).unwrap()).unwrap();
        // println!("json2: {}", json2);
        // println!("str: {}", str);

        json2.obj_iter().unwrap().for_each(|(key, value)| {
            println!("obj_iter: key: {:?}, value: {:?}", key, value);
        });
    }

    #[test]
    fn test_obj_mut_iter() {
        let str = "{\"first name\":\"Yiran\", \"last name\": \"王\", \"age\":20,\"is_student\":true,\"courses\":[{\"name\":\"CPEN 212\",\"credits\":4},{\"name\":\"CPSC 221\",\"credits\":4},{\"name\":\"Math 256\",\"credits\":3}],\"address\":{\"street\":\"1935 Lower Mall\",\"city\":\"Vancouver\",\"postal_code\":\"V6T 1X1\"},\"friends\":[{\"name\":\"Tommy\",\"age\":20},{\"name\":\"Joe\",\"age\":20}],\"graduated\":false, \"university\": \"UBC\"}";
        let list = json_lexer::parse_all(str).unwrap();
        // println!("list: {:?}", list);
        let mut json_str = parse_all(list).unwrap();
        // println!("json_str: {:?}", json_str);
        let json = json_str.dump(2, false);
        // println!("json: {}", json);

        let mut json2 = parse_all(json_lexer::parse_all(&json).unwrap()).unwrap();
        // println!("json2: {}", json2);
        // println!("str: {}", str);

        json2.obj_mut_iter().unwrap().for_each(|(key, value)| {
            *value = JsonNode::String("test".parse().unwrap());
            println!("obj_mut_iter: key: {:?}, value: {:?}", key, value);
        });
    }

    #[test]
    fn test_obj_into_iter() {
        let str = "{\"first name\":\"Yiran\", \"last name\": \"王\", \"age\":20,\"is_student\":true,\"courses\":[{\"name\":\"CPEN 212\",\"credits\":4},{\"name\":\"CPSC 221\",\"credits\":4},{\"name\":\"Math 256\",\"credits\":3}],\"address\":{\"street\":\"1935 Lower Mall\",\"city\":\"Vancouver\",\"postal_code\":\"V6T 1X1\"},\"friends\":[{\"name\":\"Tommy\",\"age\":20},{\"name\":\"Joe\",\"age\":20}],\"graduated\":false, \"university\": \"UBC\"}";
        let list = json_lexer::parse_all(str).unwrap();
        // println!("list: {:?}", list);
        let mut json_str = parse_all(list).unwrap();
        // println!("json_str: {:?}", json_str);
        let json = json_str.dump(2, false);
        // println!("json: {}", json);

        let json2 = parse_all(json_lexer::parse_all(&json).unwrap()).unwrap();
        // println!("json2: {}", json2);
        // println!("str: {}", str);
        json2.obj_into_iter().unwrap().for_each(|(_, value)| {
            // println!("key: {:?}, value: {:?}", key, value);
            match value {
                JsonNode::Array(value) => {
                    println!("obj_into_iter: value: {:?}", value);
                }
                _ => (),
            }
        });
    }

    #[test]
    fn test_arr_iter() {
        // 创建一个 JsonNode::Array
        let json = JsonNode::Array(vec![
            JsonNode::String("item1".to_string()),
            JsonNode::Number(42.0),
            JsonNode::Boolean(true),
        ]);

        // 测试 arr_iter
        let iter = json.arr_iter().unwrap(); // 应该返回 Some
        let items: Vec<&JsonNode> = iter.collect(); // 收集所有元素

        // 验证迭代器的内容
        assert_eq!(items.len(), 3);
        assert!(matches!(items[0], JsonNode::String(s) if s == "item1"));
        assert!(matches!(items[1], JsonNode::Number(n) if n == &42.0));
        assert!(matches!(items[2], JsonNode::Boolean(b) if b == &true));

        // 测试非数组类型返回 None
        let json_string = JsonNode::String("not an array".to_string());
        assert!(json_string.arr_iter().is_none());
    }

    #[test]
    fn test_arr_mut_iter() {
        // 创建一个 JsonNode::Array
        let mut json = JsonNode::Array(vec![
            JsonNode::String("item1".to_string()),
            JsonNode::Number(42.0),
            JsonNode::Boolean(true),
        ]);

        // 测试 arr_mut_iter
        if let Some(mut iter) = json.arr_mut_iter() {
            // 修改数组中的元素
            for node in iter {
                match node {
                    JsonNode::String(s) => s.push_str("_modified"),
                    JsonNode::Number(n) => *n += 1f64,
                    JsonNode::Boolean(b) => *b = false,
                    _ => {}
                }
            }
        }

        // 验证修改是否生效
        match &json {
            JsonNode::Array(arr) => {
                // 使用引用访问 arr 中的元素
                // assert!(matches!(arr[0], JsonNode::String(s) if s == "item1_modified"));
                assert!(matches!(arr[1], JsonNode::Number(n) if n == 43.0));
                assert!(matches!(arr[2], JsonNode::Boolean(b) if b == false));
            }
            _ => panic!("Expected JsonNode::Array"),
        }

        // 测试非数组类型返回 None
        let mut json_string = JsonNode::String("not an array".to_string());
        assert!(json_string.arr_mut_iter().is_none());
    }

    #[test]
    fn test_arr_into_iter() {
        // 创建一个 JsonNode::Array
        let json = JsonNode::Array(vec![
            JsonNode::String("item1".to_string()),
            JsonNode::Number(42.0),
            JsonNode::Boolean(true),
        ]);

        // 测试 arr_into_iter
        let iter = json.arr_into_iter().unwrap(); // 应该返回 Some
        let items: Vec<JsonNode> = iter.collect(); // 收集所有元素

        // 验证迭代器的内容
        // assert_eq!(items.len(), 3);
        // assert!(matches!(items[0], JsonNode::String(s) if s == "item1"));
        // assert!(matches!(items[1], JsonNode::Number(n) if n == 42.0));
        // assert!(matches!(items[2], JsonNode::Boolean(b) if b == true));
        for i in items.iter() {
            match i {
                JsonNode::String(str) => {
                    if str == "item1" {
                        println!("str")
                    }
                }
                JsonNode::Number(num) => {
                    if *num == 42.0 {
                        println!("num")
                    }
                }
                JsonNode::Boolean(bool) => {
                    if *bool {
                        println!("bool")
                    }
                }
                _ => (),
            }
        }

        // 测试非数组类型返回 None
        let json_string = JsonNode::String("not an array".to_string());
        assert!(json_string.arr_into_iter().is_none());
    }
}
